package com.work.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;

/**
 * The Class GenericDAO.
 *
 * @author "Mihai Roman"
 * @param <T> the generic type
 */
public abstract class GenericDAO<T> {

	/** The Constant UNIT_NAME. */
	private final static String UNIT_NAME = "SCRUM";
	
	@PersistenceContext(unitName = UNIT_NAME)
	private EntityManager em;
	
	private final Class<T> entityClass;
	
	public GenericDAO(Class<T> entityClass) {
		this.entityClass = entityClass;
	}
	
	/**
	 * Save.
	 *
	 * @param entity the entity
	 */
	public void save(T entity) {
		save(entity,true);
	}
	
	/**
	 * Save.
	 *
	 * @param entity the entity
	 * @param flush the flush
	 */
	public void save(T entity, boolean flush){
		em.persist(entity);
		if(flush){
			em.flush();
		}
	}
	
	/**
	 * Delete.
	 *
	 * @param entity the entity
	 */
	public void delete(T entity) {
		T entityToBeRemoved = em.merge(entity);
		
		em.remove(entityToBeRemoved);
	}

	/**
	 * Update.
	 *
	 * @param entity the entity
	 * @return the t
	 */
	public T update(T entity) {
		return update(entity,false);
	}
	
	/**
	 * Update.
	 *
	 * @param entity the entity
	 * @param flush the flush
	 * @return the t
	 */
	public T update(T entity, boolean flush) {
		T persisted = em.merge(entity);
		if(flush){
			em.flush();
		}
		return persisted;
	}
	
	/**
	 * Gets the em.
	 *
	 * @return the em
	 */
	public EntityManager getEm() {
		return em;
	}

	/**
	 * Sets the em.
	 *
	 * @param em the new em
	 */
	public void setEm(EntityManager em) {
		this.em = em;
	}
	
	public T findById(int entityID) {
		return em.find(entityClass, entityID);
	}
	
	public T findById(int entityID, LockModeType lockMode) {
		return em.find(entityClass, entityID, lockMode);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<T> findAll() {
		CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
		cq.select(cq.from(entityClass));
		return em.createQuery(cq).getResultList();
	}
	
}
